<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-alpha.63">
<title data-react-helmet="true">2.2 选项 | Fur</title><meta data-react-helmet="true" name="docsearch:version" content="current,latest"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:title" content="2.2 选项 | Fur"><meta data-react-helmet="true" name="description" content="2.2.1 什么是选项"><meta data-react-helmet="true" property="og:description" content="2.2.1 什么是选项"><meta data-react-helmet="true" property="og:url" content="https://furos.cn/docs/options"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://furos.cn/docs/options"><link rel="stylesheet" href="/styles.83aacb78.css">
<link rel="preload" href="/styles.16c5981f.js" as="script">
<link rel="preload" href="/runtime~main.e25f3aa1.js" as="script">
<link rel="preload" href="/main.b54c8f62.js" as="script">
<link rel="preload" href="/1.0b36cbc2.js" as="script">
<link rel="preload" href="/2.17909aba.js" as="script">
<link rel="preload" href="/3.f42eda22.js" as="script">
<link rel="preload" href="/1be78505.c23a6c85.js" as="script">
<link rel="preload" href="/31.92e96840.js" as="script">
<link rel="preload" href="/f976f453.bd53d64a.js" as="script">
<link rel="preload" href="/17896441.c3d5fc96.js" as="script">
<link rel="preload" href="/e1713ffa.d7a29825.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<nav class="navbar navbar--light navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><div aria-label="Navigation bar toggle" class="navbar__toggle" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></div><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/">Next</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs">文档</a><a class="navbar__item navbar__link" href="/blog">博客</a><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">配置</a></div><div class="navbar__items navbar__items--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">视频</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">工具</a><ul class="dropdown__menu"><li><a target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">代码生成器</a></li></ul></div><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">看板</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">仓库</a><ul class="dropdown__menu"><li><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">Gitee</a></li><li><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">GitHub</a></li></ul></div><div class="react-toggle react-toggle--disabled displayOnlyInLargeViewport_2aTZ"><div class="react-toggle-track"><div class="react-toggle-track-check"><span class="toggle_BsTx">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_BsTx">🌞</span></div></div><div class="react-toggle-thumb"></div><input type="checkbox" disabled="" aria-label="Dark mode toggle" class="react-toggle-screenreader-only"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div><div class="navbar-sidebar"><div class="navbar-sidebar__brand"><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a></div><div class="navbar-sidebar__items"><div class="menu"><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">Versions</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link navbar__link--active" href="/docs">文档</a></li><li class="menu__list-item"><a class="menu__link" href="/blog">博客</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">配置</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">视频</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">工具</a><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link" position="left">代码生成器</a></li></ul></li><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="menu__link">看板</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">仓库</a><ul class="menu__list"><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">Gitee</a></li><li class="menu__list-item"><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">GitHub</a></li></ul></li></ul></div></div></div></nav><div class="main-wrapper"><div class="docPage_2gpo"><div class="docSidebarContainer_3_JD" role="complementary"><div class="sidebar_2urC"><div class="menu menu--responsive menu_5FrY"><button aria-label="Open Menu" aria-haspopup="true" class="button button--secondary button--sm menu__button" type="button"><svg aria-label="Menu" class="sidebarMenuIcon_Dm3K" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 32 32" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><ul class="menu__list"><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">1. 框架介绍</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/">1.1 介绍</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/author">1.2 关于作者</a></li></ul></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#!">2. 配置与选项</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/configuration">2.1 配置</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" tabindex="0" href="/docs/options">2.2 选项</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/dynamic-api-controller">3. 动态 WebAPI</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/specification-document">4. 规范化接口文档</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/friendly-exception">5. 友好异常处理</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/data-validation">6. 数据校验</a></li></ul></div></div></div><main class="docMainContainer_3EyW"><div class="container padding-vert--lg docItemWrapper_1EkI"><div class="row"><div class="col docItemCol_2ASc"><div class="docItemContainer_3QWW"><article><header><h1 class="docTitle_1Lrw">2.2 选项</h1></header><div class="markdown"><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="221-什么是选项"></a>2.2.1 什么是选项<a aria-hidden="true" tabindex="-1" class="hash-link" href="#221-什么是选项" title="Direct link to heading">#</a></h2><p>选项是 <code>ASP.NET Core</code> 推荐的动态读取配置的方式，这种方式将配置文件数据用一个<strong>强类型</strong>来托管，能够实现配置验证、默认值配置、实时读取等功能。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="222-与配置的区别"></a>2.2.2 与配置的区别<a aria-hidden="true" tabindex="-1" class="hash-link" href="#222-与配置的区别" title="Direct link to heading">#</a></h2><p>选项实际上也是配置，但在后者的基础上添加了配置验证、默认值/后期配置设定及提供了多种接口读取配置信息，同时还支持供配置更改通知等强大灵活功能。</p><p>所以，除了一次性读取使用的配置以外，都应该选用 <strong>选项</strong> 替换 <strong>配置</strong>。</p><div class="admonition admonition-tip alert alert--success"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>知识导航</h5></div><div class="admonition-content"><p>有关配置说明可查看《<a href="/docs/configuration">2.1 配置</a>》 章节。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="223-选项的使用"></a>2.2.3 选项的使用<a aria-hidden="true" tabindex="-1" class="hash-link" href="#223-选项的使用" title="Direct link to heading">#</a></h2><p>假设我们需要在系统运行时获取<strong>系统名称、版本号及版权信息</strong>，这些信息可能随时变化而且需要在多个地方使用。这时就需要将这些信息配置起来。具体步骤如下：</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="配置-appsettingsjson-信息"></a>配置 <code>appsettings.json</code> 信息<a aria-hidden="true" tabindex="-1" class="hash-link" href="#配置-appsettingsjson-信息" title="Direct link to heading">#</a></h3><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-json codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">&quot;AppInfo&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;Name&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Fur&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;Version&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;1.0.0&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;Company&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Baiqian&quot;</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="创建-appinfooptions-强类型类"></a>创建 <code>AppInfoOptions</code> 强类型类<a aria-hidden="true" tabindex="-1" class="hash-link" href="#创建-appinfooptions-强类型类" title="Direct link to heading">#</a></h3><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.ConfigurableOptions;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class AppInfoOptions : IConfigurableOptions</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Version { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>温馨提示</h5></div><div class="admonition-content"><p>建议所有选项类都应该以 <strong><code>Options</code></strong> 命名结尾。</p><p>另外，<code>Fur</code> 框架提供了非常灵活的注册选项服务的方法，只需要继承 <strong><code>IConfigurableOptions</code></strong> 接口即可，该接口位于 <strong><code>Fur.ConfigurableOptions</code></strong> 命名空间下。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="注册-appinfooptions-服务"></a>注册 <code>AppInfoOptions</code> 服务<a aria-hidden="true" tabindex="-1" class="hash-link" href="#注册-appinfooptions-服务" title="Direct link to heading">#</a></h3><p>选项不同于配置，需在应用启动时注册：</p><div class="mdxCodeBlock_1XEh"><div style="color:#bfc7d5;background-color:#292d3e" class="codeBlockTitle_3nn1">Fur.Web.Entry/Startup.cs</div><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd undefined">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC codeBlockWithTitle_3QsD"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Builder;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Hosting;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.Configuration;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class Startup</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public Startup(IConfiguration configuration)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            Configuration = configuration;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public IConfiguration Configuration { get; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void ConfigureServices(IServiceCollection services)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            services.AddApp(options =&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                options.AddConfigurableOptions&lt;AppInfoOptions&gt;();</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            });</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-caution alert alert--warning"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>特别注意</h5></div><div class="admonition-content"><p><code>services.AddConfigurableOptions&lt;AppInfoOptions&gt;()</code> 只能在 <code>services.AddApp()</code> <strong>之后或参数内</strong>注册。</p><p><strong>下面代码是无效的</strong>：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">services.AddConfigurableOptions&lt;AppInfoOptions&gt;();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">services.AddApp();</span></div></div></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>应用注册说明</h5></div><div class="admonition-content"><p>在 <code>ASP.NET Core</code> 应用程序中，<strong>注册服务</strong> 指的是在 <code>启用项目</code> 中 <code>Startup.cs</code> 类 <code>ConfigureServices</code> 方法中注册。</p><p>在 <code>Fur</code> 框架中，<code>Startup.cs</code> 路径为：<strong><code>Fur.Web.Entry/Startup.cs</code></strong></p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="读取-appinfooptions-信息"></a>读取 <code>AppInfoOptions</code> 信息<a aria-hidden="true" tabindex="-1" class="hash-link" href="#读取-appinfooptions-信息" title="Direct link to heading">#</a></h3><p>在 <code>Fur</code> 框架中，提供了多种读取方式：</p><ul><li>通过 <code>App.GetOptions&lt;TOptions&gt;(jsonKey)</code> 读取（<strong>不推荐</strong>）</li><li>通过依赖注入以下实例读取：<ul><li><code>IOptions&lt;TOptions&gt;</code></li><li><code>IOptionsSnapshot&lt;TOptions&gt;</code></li><li><code>IOptionsMonitor&lt;TOptions&gt;</code></li></ul></li><li>通过 <code>App</code> 静态类提供的静态方法获取：<ul><li><code>App.GetOptions&lt;TOptions&gt;()</code></li><li><code>App.GetOptionsMonitor&lt;TOptions&gt;()</code></li><li><code>App.GetOptionsSnapshot&lt;TOptions&gt;()</code></li></ul></li></ul><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_1w39 tabs__item--active" style="outline:none">App.GetOptions&lt;TOptions&gt;(jsonKey)</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">依赖注入方式</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">App.GetOptions&lt;TOptions&gt;()</li></ul><div role="tabpanel" class="margin-vert--md"><div><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Route(&quot;api/[controller]&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class DefaultController : ControllerBase</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [HttpGet]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Get()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            // 不推荐采用此方式读取</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            var appInfo = App.GetOptions&lt;AppInfoOptions&gt;(&quot;AppInfo&quot;);</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            return $@&quot;名称：{appInfo.Name}，</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                      版本：{appInfo.Version}，</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">                      公司：{appInfo.Company}&quot;;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div></div></div></div><div class="admonition admonition-caution alert alert--warning"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>特别注意</h5></div><div class="admonition-content"><p><code>App.GetOptions&lt;TOptions&gt;(jsonKey)</code> 静态方法 区别于没有参数的 <code>App.GetOptions&lt;TOptions&gt;()</code> 静态方法，前者实际上还是 <strong>配置</strong>，只不过做了强类型解析，后者则通过 <code>IOptions&lt;TOptions&gt;</code> 解析。</p><p>两者源码如下：</p><div class="mdxCodeBlock_1XEh"><div style="color:#bfc7d5;background-color:#292d3e" class="codeBlockTitle_3nn1">Fur/App/App.cs</div><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd undefined">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC codeBlockWithTitle_3QsD"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.Configuration;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.Options;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    /// 全局应用类</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public static class App</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 获取选项</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;typeparam name=&quot;TOptions&quot;&gt;强类型选项类&lt;/typeparam&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;param name=&quot;jsonKey&quot;&gt;配置中对应的Key&lt;/param&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;returns&gt;&lt;/returns&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public static TOptions GetOptions&lt;TOptions&gt;(string jsonKey)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            where TOptions : class</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            =&gt; Configuration.GetSection(jsonKey).Get&lt;TOptions&gt;();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 获取选项</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;typeparam name=&quot;TOptions&quot;&gt;强类型选项类&lt;/typeparam&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;returns&gt;&lt;/returns&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public static TOptions GetOptions&lt;TOptions&gt;()</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            where TOptions : class</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            =&gt; ServiceProvider.GetService&lt;IOptions&lt;TOptions&gt;&gt;().Value;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // Other Codes...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>通过上述代码得知，为什么不推荐使用 <code>App.GetOptions&lt;TOptions&gt;(jsonKey)</code> 读取，因为这种方式无法应用选项验证、默认配置、更改通知等功能。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="如何选择读取方式"></a>如何选择读取方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#如何选择读取方式" title="Direct link to heading">#</a></h3><ul><li>如果选项需要在多个地方使用，则无论任何时候都不推荐使用 <code>App.GetOptions&lt;TOptions&gt;(jsonKey)</code></li><li>在可依赖注入类中，依赖注入 <code>IOptions[Snapshot|Monitor]&lt;TOptions&gt;</code> 读取</li><li>在静态类/非依赖注入类中，选择 <code>App.GetOptions[Snapshot|Monitor]&lt;TOptions&gt;()</code> 读取</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="224-选项接口说明"></a>2.2.4 选项接口说明<a aria-hidden="true" tabindex="-1" class="hash-link" href="#224-选项接口说明" title="Direct link to heading">#</a></h2><p><code>ASP.NET Core</code> 应用提供了多种读取选项的接口：</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="接口说明"></a>接口说明<a aria-hidden="true" tabindex="-1" class="hash-link" href="#接口说明" title="Direct link to heading">#</a></h3><ul><li><code>IOptions&lt;TOptions&gt;</code>：<ul><li>不支持：<ul><li>在应用启动后读取配置数据</li><li>命名选项</li></ul></li><li>注册为单一实例且可以注入到任何服务生存期</li></ul></li><li><code>IOptionsSnapshot&lt;TOptions&gt;</code>：<ul><li>在每次请求时应重新计算选项的方案中有用</li><li>注册为范围内，因此无法注入到单一实例服务</li><li>支持命名选项</li></ul></li><li><code>IOptionsMonitor&lt;TOptions&gt;</code>：<ul><li>用于检索选项并管理 TOptions 实例的选项通知。</li><li>注册为单一实例且可以注入到任何服务生存期。</li><li>支持：<ul><li>更改通知</li><li>命名选项</li><li>可重载配置</li><li>选择性选项失效 <code>(IOptionsMonitorCache&lt;TOptions&gt;)</code></li></ul></li></ul></li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="了解更多"></a>了解更多<a aria-hidden="true" tabindex="-1" class="hash-link" href="#了解更多" title="Direct link to heading">#</a></h3><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>了解更多</h5></div><div class="admonition-content"><p>想了解更多 <code>选项接口</code> 知识可查阅 <a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0#options-interfaces" target="_blank" rel="noopener noreferrer">ASP.NET Core - 选项 - 选项接口</a> 小节。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="225-选项自定义配置"></a>2.2.5 选项自定义配置<a aria-hidden="true" tabindex="-1" class="hash-link" href="#225-选项自定义配置" title="Direct link to heading">#</a></h2><p>我们知道，选项实际上需要和配置文件特定键值挂钩，那 <code>Fur</code> 是如何准确的找到配置文件中的键值的呢？</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="选项查找键流程"></a>选项查找键流程<a aria-hidden="true" tabindex="-1" class="hash-link" href="#选项查找键流程" title="Direct link to heading">#</a></h3><ul><li><strong>没有贴 <code>[OptionsSettings]</code> 特性</strong><ul><li>以 <code>Options</code> 结尾，则去除 <code>Options</code> 字符串</li><li>否则返回 <code>类名称</code></li></ul></li><li><strong>贴了 <code>[OptionsSettings]</code> 特性</strong><ul><li>如果配置了 <code>JsonKey</code> 属性，则返回 <code>JsonKey</code> 的值</li><li>否则返回 <code>类名称</code></li></ul></li></ul><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_1w39 tabs__item--active" style="outline:none">无[OptionsSettings]</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">有[OptionsSettings]</li></ul><div role="tabpanel" class="margin-vert--md"><div><ul><li>以 <code>Options</code> 结尾，则键名为：<code>AppInfo</code></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">public class AppInfoOptions : IConfigurableOptions</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Version { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><ul><li>不以 <code>Options</code> 结尾，则键名为：<code>AppInfoSettings</code></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">public class AppInfoSettings : IConfigurableOptions</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Version { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="optionssettings-配置说明"></a><code>[OptionsSettings]</code> 配置说明<a aria-hidden="true" tabindex="-1" class="hash-link" href="#optionssettings-配置说明" title="Direct link to heading">#</a></h3><ul><li><code>JsonKey</code>：对应配置文件中的键，支持 <strong>分层键</strong> 字符串，参见：《<a href="/docs/configuration#%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E8%AF%BB%E5%8F%96%E6%96%B9%E5%BC%8F">2.2 配置 - 2.1.3 分层读取数据</a>》</li><li><code>PostConfigureAll</code>：选项后期配置，默认 <code>false</code>。<a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1#options-post-configuration" target="_blank" rel="noopener noreferrer">ASP.NET Core - 选项 - 选项后期配置</a></li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="226-选项验证"></a>2.2.6 选项验证<a aria-hidden="true" tabindex="-1" class="hash-link" href="#226-选项验证" title="Direct link to heading">#</a></h2><p>选项支持验证配置有效性，在 <code>Fur</code> 框架中，通过 <code>services.AddConfigurableOptions&lt;TOptions&gt;()</code> 注册选项默认启用了验证支持。</p><p>包括：</p><ul><li>特性方式 <code>DataAnnotations</code></li><li>自定义复杂验证 <code>IValidateOptions&lt;TOptions&gt;</code></li></ul><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_1w39 tabs__item--active" style="outline:none">特性方式</li><li role="tab" tabindex="0" aria-selected="false" class="tabs__item tabItem_1w39" style="outline:none">复杂验证</li></ul><div role="tabpanel" class="margin-vert--md"><div><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.ConfigurableOptions;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.ComponentModel.DataAnnotations;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class AppInfoOptions : IConfigurableOptions</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required(ErrorMessage = &quot;名称不能为空&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required, RegularExpression(@&quot;^[0-9][0-9\.]+[0-9]$&quot;, ErrorMessage = &quot;不是有效的版本号&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Version { get; set; }</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        [Required, MaxLength(100)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>特别说明</h5></div><div class="admonition-content"><p><strong><code>IConfigurableOptions&lt;TOptions, TOptionsValidation&gt;</code></strong> 继承自 <strong><code>IConfigurableOptions&lt;TOptions&gt;</code></strong>，也就是自定义复杂验证默认具有 <strong><code>PostConfigure(TOptions options)</code></strong> 选项后期配置方法。关于《<a href="#227-%E9%80%89%E9%A1%B9%E5%90%8E%E6%9C%9F%E9%85%8D%E7%BD%AE">2.2.7 选项后期配置</a>》将在下一小节说明。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="227-选项后期配置"></a>2.2.7 选项后期配置<a aria-hidden="true" tabindex="-1" class="hash-link" href="#227-选项后期配置" title="Direct link to heading">#</a></h2><p>选项后期配置通俗一点来说，可以在运行时解析值或设定默认值/后期配置等。</p><p>在 <code>Fur</code> 框架中，配置选项后期配置很简单，只需要继承 <code>IConfigurableOptions&lt;TOptions</code> 接口并实现 <code>PostConfigure(TOptions options)</code> 方法。</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.ConfigurableOptions;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.Extensions.Configuration;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System.ComponentModel.DataAnnotations;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class AppInfoOptions : IConfigurableOptions&lt;AppInfoOptions&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [Required(ErrorMessage = &quot;名称不能为空&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [Required]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Version { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [Required, MaxLength(100)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public void PostConfigure(AppInfoOptions options, IConfiguration configuration)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            options.Name ??= &quot;Fur&quot;;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            options.Version ??= &quot;1.0.0&quot;;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            options.Version ??= &quot;Baiqian&quot;;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>特别说明</h5></div><div class="admonition-content"><p><strong><code>IConfigurableOptions&lt;TOptions, TOptionsValidation&gt;</code></strong> 继承自 <strong><code>IConfigurableOptions&lt;TOptions&gt;</code></strong>，也就是自定义复杂验证默认具有 <strong><code>PostConfigure(TOptions options, IConfiguration configuration)</code></strong> 选项后期配置方法。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="228-选项更改通知（热更新）"></a>2.2.8 选项更改通知（<code>热更新</code>）<a aria-hidden="true" tabindex="-1" class="hash-link" href="#228-选项更改通知（热更新）" title="Direct link to heading">#</a></h2><p><code>Fur</code> 框架提供了非常简单且灵活的方式监听选项更改，也就是 <strong><code>appsettings.json</code> 或 自定义配置文件发生任何更改都会触发处理方法</strong>。</p><p>使用非常简单，只需要继承 <code>IConfigurableOptionsListener&lt;TOptions&gt;</code> 接口并实现 <code>void OnListener(TOptions options, IConfiguration configuration)</code> 方法即可。</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.ConfigurableOptions;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class AppInfoOptions : IConfigurableOptionsListener&lt;AppInfoOptions&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Name { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Version { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string Company { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public void OnListener(AppInfoOptions options, IConfiguration configuration)</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        var name = options.Name;  // 实时的最新值</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        var version = options.Version;  // 实时的最新值</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public void PostConfigure(AppInfoOptions options, IConfiguration configuration)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>特别说明</h5></div><div class="admonition-content"><p><strong><code>IConfigurableOptionsListener&lt;TOptions&gt;</code></strong> 继承自 <strong><code>IConfigurableOptions&lt;TOptions&gt;</code></strong>。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="229-选项的优缺点"></a>2.2.9 选项的优缺点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#229-选项的优缺点" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="优点"></a>优点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#优点" title="Direct link to heading">#</a></h3><ul><li>强类型配置</li><li>提供多种读取方式</li><li>支持热加载</li><li>支持设置默认值/后期配置</li><li>支持在运行环境中动态配置</li><li>支持验证配置有效性</li><li>支持更改通知</li><li>支持命名选项</li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="缺点"></a>缺点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#缺点" title="Direct link to heading">#</a></h3><ul><li>需要定义对应类型</li><li>需要在启动时注册</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="2210-反馈与建议"></a>2.2.10 反馈与建议<a aria-hidden="true" tabindex="-1" class="hash-link" href="#2210-反馈与建议" title="Direct link to heading">#</a></h2><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>与我们交流</h5></div><div class="admonition-content"><p>给 Fur 提 <a href="https://gitee.com/monksoul/Fur/issues/new?issue" target="_blank" rel="noopener noreferrer">Issue</a>。</p></div></div><hr><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>了解更多</h5></div><div class="admonition-content"><p>想了解更多 <code>选项</code> 知识可查阅 <a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0" target="_blank" rel="noopener noreferrer">ASP.NET Core - 选项</a> 章节。</p></div></div></div></article><div class="margin-vert--xl"><div class="row"><div class="col"><a href="https://gitee.com/monksoul/Fur/tree/alpha/docs/docs/options.mdx" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="1.2em" width="1.2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 40 40" style="margin-right:0.3em;vertical-align:sub"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div></div></div><div class="margin-vert--lg"><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/configuration"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 2.1 配置</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/docs/dynamic-api-controller"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">3. 动态 WebAPI »</div></a></div></nav></div></div></div><div class="col col--3"><div class="tableOfContents_3SO_"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#221-什么是选项" class="table-of-contents__link">2.2.1 什么是选项</a></li><li><a href="#222-与配置的区别" class="table-of-contents__link">2.2.2 与配置的区别</a></li><li><a href="#223-选项的使用" class="table-of-contents__link">2.2.3 选项的使用</a><ul><li><a href="#配置-appsettingsjson-信息" class="table-of-contents__link">配置 <code>appsettings.json</code> 信息</a></li><li><a href="#创建-appinfooptions-强类型类" class="table-of-contents__link">创建 <code>AppInfoOptions</code> 强类型类</a></li><li><a href="#注册-appinfooptions-服务" class="table-of-contents__link">注册 <code>AppInfoOptions</code> 服务</a></li><li><a href="#读取-appinfooptions-信息" class="table-of-contents__link">读取 <code>AppInfoOptions</code> 信息</a></li><li><a href="#如何选择读取方式" class="table-of-contents__link">如何选择读取方式</a></li></ul></li><li><a href="#224-选项接口说明" class="table-of-contents__link">2.2.4 选项接口说明</a><ul><li><a href="#接口说明" class="table-of-contents__link">接口说明</a></li><li><a href="#了解更多" class="table-of-contents__link">了解更多</a></li></ul></li><li><a href="#225-选项自定义配置" class="table-of-contents__link">2.2.5 选项自定义配置</a><ul><li><a href="#选项查找键流程" class="table-of-contents__link">选项查找键流程</a></li><li><a href="#optionssettings-配置说明" class="table-of-contents__link"><code>[OptionsSettings]</code> 配置说明</a></li></ul></li><li><a href="#226-选项验证" class="table-of-contents__link">2.2.6 选项验证</a></li><li><a href="#227-选项后期配置" class="table-of-contents__link">2.2.7 选项后期配置</a></li><li><a href="#228-选项更改通知（热更新）" class="table-of-contents__link">2.2.8 选项更改通知（<code>热更新</code>）</a></li><li><a href="#229-选项的优缺点" class="table-of-contents__link">2.2.9 选项的优缺点</a><ul><li><a href="#优点" class="table-of-contents__link">优点</a></li><li><a href="#缺点" class="table-of-contents__link">缺点</a></li></ul></li><li><a href="#2210-反馈与建议" class="table-of-contents__link">2.2.10 反馈与建议</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links"><div class="col footer__col"><h4 class="footer__title">文档</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs">入门</a></li><li class="footer__item"><a class="footer__link-item" href="/docs">指南</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">社区</h4><ul class="footer__items"><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">更多</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">博客</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库</a></li></ul></div></div><div class="text--center"><div>Copyright © 2020 Fur, Baiqian Co.,Ltd.</div></div></div></footer></div>
<script src="/styles.16c5981f.js"></script>
<script src="/runtime~main.e25f3aa1.js"></script>
<script src="/main.b54c8f62.js"></script>
<script src="/1.0b36cbc2.js"></script>
<script src="/2.17909aba.js"></script>
<script src="/3.f42eda22.js"></script>
<script src="/1be78505.c23a6c85.js"></script>
<script src="/31.92e96840.js"></script>
<script src="/f976f453.bd53d64a.js"></script>
<script src="/17896441.c3d5fc96.js"></script>
<script src="/e1713ffa.d7a29825.js"></script>
</body>
</html>